# -*- coding: utf-8 -*-

'''
Created on May 4, 2011

@author: peterd
'''

from sgmllib import SGMLParser
import re
import unicodedata as ud

import time

from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.template.loader import get_template
from django.template import Context


from mhd.models import MHD_Link_Stop, MHD_Link, MHD_Link_Type, MHD_Link_Direction, MHD_Stop 

class MHD_LinkStopListParser(SGMLParser):
    
    def __init__(self):
        SGMLParser.__init__(self)
        self.in_begin_graficon_ = False
        self.in_stop_ = False
        self.routes_ = []
        self.cur_route_ = []
        self.cur_stop_name_ = None
        self.stop_id_ = None
        self.cur_stop_timetable_url_ = None
        self.cur_direction_ = None
        self.directions_ = []
        
                
    def parse(self, htmlPage):
        self.feed(htmlPage)        
        self.close()
        return self.routes_
                
    def handle_data(self, data):
        if data.find(u'Vyhľadávanie liniek a zastávok') != -1:
            if len(self.cur_route_) > 0:
                self.routes_.append({'direction': self.cur_direction_, 'stops': self.cur_route_})
                self.cur_route_ = []
            return

        if data.find('Smer') != -1:
            if len(self.cur_route_) > 0:
                self.routes_.append({'direction': self.cur_direction_, 'stops': self.cur_route_})
                self.cur_route_ = []
            self.cur_direction_ = data.replace('Smer:', '').strip()
            # HACK: direction must be unique
            if self.cur_direction_ in self.directions_:
                self.cur_direction_ = '%s - II' % (self.cur_direction_)
            self.directions_.append(self.cur_direction_)
            return
            
        if data.find(u'Odchody zo zastávky') != -1:
            self.in_begin_graficon_ = True

        if self.in_stop_:
            # no stop_id found, use 0
            if self.cur_stop_name_:
                self.cur_route_.append({'name': self.cur_stop_name_, 'id': 0, 'timetable_url': self.cur_stop_timetable_url_})
                self.stop_id_ = None
            self.cur_stop_name_ = data

    def start_td(self, attrs):
        for attr, value in attrs:            
            if attr == 'style' and value.find('border-right:0px; border-top:0px; border-bottom:1px dotted;') != -1 \
                or value.find('border-right:0px; border-top:0px; padding-top:2px; padding-bottom:0px;') != -1:
                self.in_stop_ = True
                break
            
    def end_td(self):
        if self.in_stop_:
            self.in_stop_ = False            
            
    def start_a(self, attrs):
        for attr, value in attrs:
            if attr == 'href':
                if value.find('javascript:Mapa') != -1:
                    m = re.match('.*?(\d+).*?', value)
                    if m:
                        self.stop_id_ = m.group(1)
                elif self.in_stop_:
                    self.cur_stop_timetable_url_ = value
            
    def end_a(self):
        if self.stop_id_:
            self.cur_route_.append({'name': self.cur_stop_name_, 'id': self.stop_id_, 'timetable_url': self.cur_stop_timetable_url_})
            self.stop_id_ = None
            self.cur_stop_timetable_url_ = None
            self.cur_stop_name_ = None            


class MHD_LinkTimetableParser(SGMLParser):

    def __init__(self):
        SGMLParser.__init__(self)
        self.timetable_ = {}
        self.in_stop_delta_ = False
        self.in_stop_zone_ = False
        self.in_stop_name_ = False
        self.stops_ = {}
        self.cur_stop_ = {}
        self.num_stops_ = 0
        self.stop_num_ = 1        
        self.in_hour_ = False
        self.in_minutes_ = False
        self.all_days_tt_ = []
        self.wrk_days_school_tt_ = []
        self.wrk_days_noschool_tt_ = []
        self.weekend_tt_ = []
        self.in_timetable_ = False
        self.cur_hour_ = None
        self.tt_map_ = {}
        self.tt_idx_ = 0
        self.tt_idx2_ = -1
        
    
    def parse(self, htmlPage, link, direction):
        self.link_ = link
        self.direction_ = direction
        self.feed(htmlPage)        
        self.close()
        
        self.timetable_['link'] = self.link_
        self.timetable_['direction'] = self.direction_
        self.timetable_['all_days'] =  self.all_days_tt_
        if len(self.timetable_['all_days']):
            self.timetable_['work_days_school'] = self.all_days_tt_
            self.timetable_['work_days_noschool'] = self.all_days_tt_
            self.timetable_['weekend'] = self.all_days_tt_
        else:
            self.timetable_['work_days_school'] = self.wrk_days_school_tt_
            self.timetable_['work_days_noschool'] = self.wrk_days_noschool_tt_
            self.timetable_['weekend'] =  self.weekend_tt_
        self.timetable_['stops'] = self.stops_
        
        return self.timetable_
    
    
    def start_b(self, attrs):
        if self.in_timetable_:
            self.in_hour_ = True
               
                    
    def end_b(self):
        if self.in_hour_:
            self.in_hour_ = False                    
    
        
    def handle_data(self, data):
        data = data.strip()
        if not data or data == u'<' or data == u'•':
            return
        
        # replace encoded spaces by conventional ones
        if data.find(u'\xa0') != -1:
            data = data.replace(u'\xa0', u'\x20')

        if data.find(u'Odchody zo zastávky:') != -1:
            self.in_stop_delta_ = False
            return 

        if data.find(u'Denne') != -1:
            self.tt_map_[self.tt_idx_] = self.all_days_tt_
        
        if data.find(u'Pracovné dni') != -1:
            if  data.find(u'prázdniny') != -1:
                self.tt_map_[self.tt_idx_] = self.wrk_days_noschool_tt_
            else:
                self.tt_map_[self.tt_idx_] = self.wrk_days_school_tt_    
            self.tt_idx_ = self.tt_idx_ + 1    
                
        if data.find(u'Voľné dni') != -1:
            self.tt_map_[self.tt_idx_] = self.weekend_tt_
                    
        if data.find(u'čas, pásmo, zastávka') != -1 or data.find(u'čas, pásmo, poznámka, zastávka') != -1:
            self.in_stop_delta_ = True
            return
            
        if self.in_stop_delta_:            
            # first comes delta min, either » or a number
            if data.find(u'»') != -1:
                self.cur_stop_['delta_min'] = 0
            else:     
                try:
                    self.cur_stop_['delta_min'] = int(data)
                except ValueError:
                    # this was probably a note that can be ignored
                    self.in_stop_delta_ = False
                    return

            # done with delta
            self.in_stop_delta_ = False
            
            # next expect zone
            self.in_stop_zone_ = True
            return
        
        if self.in_stop_zone_:
            self.cur_stop_['zone'] = int(data)
            # done with delta
            self.in_stop_zone_ = False

            # next expect name
            self.in_stop_name_ = True
            return

        if self.in_stop_name_:            
            self.cur_stop_['name'] = data
            
            # done with name
            self.in_stop_name_ = False

            self.stops_[data] = self.cur_stop_
                                    
            self.cur_stop_ = {}

            # now comes either delta of next stop or timetable data
            self.in_stop_delta_ = True
            return
        

        if data.find(u'minúta') != -1:
            self.in_timetable_ = True
            self.tt_idx2_ = self.tt_idx2_ + 1
            return

        if self.in_hour_:
            if re.match("^[0-9]+$", data):
                self.cur_hour_ = data            
                # next comes minutes
                self.in_minutes_ = True
            return
        
        if self.in_minutes_:
            if re.match("^[0-9]+$", data):
                tm = '%s:%s' % (self.cur_hour_, data)
                self.tt_map_[self.tt_idx2_].append(tm)
            return

        



# TODO: get rid off, once JourneyPlanner is finished
class MHD_RouteParser(SGMLParser):
    
    def __init__(self):
        SGMLParser.__init__(self)
        self.conns_ = []
        self.cur_conn_ = None
        self.cur_route_ = None
        self.in_link_ = False
        self.cur_link_img_ = None
        self.in_link_img_ = False
        self.in_direction_ = False
        self.in_route_details_ = False      
        self.in_stop_time_ = False                  
        self.in_stop_name_ = False
        self.in_stop_zone_ = False
        self.in_route_summary_ = False
        self.cur_stop_ = None
        self.in_walk_route_ = False
        self.conn_id_ = 1
        self.route_id_ = 1

                        
    def parse(self, htmlPage):
        self.feed(htmlPage)        
        self.close()
        return self.conns_


    def start_td(self, attrs):
        width = None
        rowspan = None
        
        for attr, value in attrs:
            if attr == 'width':
                width = value  
            if attr == 'rowspan':
                rowspan = value            
  
        if width == '50' and rowspan == '2':
            self.in_link_ = True 
            
        if width == '45' and self.in_route_details_:
            self.in_stop_time_ = True 
            
        if width == '200' and self.in_route_details_:
            self.in_stop_name_ = True 

        if width == '70' and self.in_route_details_:
            self.in_stop_zone_ = True
            
            
    def end_td(self):            
        if self.in_link_:
            self.in_link_ = False 
            
        if self.in_stop_time_:
            self.in_stop_time_ = False 
            
        if self.in_stop_name_:
            self.in_stop_name_ = False 

        if self.in_stop_zone_:
            self.in_stop_zone_ = False

            
    def start_div(self, attrs): 
        for attr, value in attrs:
            if attr == 'id' and re.search('spojenie\d{1,2}-sumar', value):
                self.in_route_summary_ = True


    def end_div(self):
        if self.in_route_summary_:
            self.in_route_summary_ = False            


    def start_table(self, attrs):
        width = None
        tclass = None
        
        for attr, value in attrs:
            if attr == 'width':
                width = value  
            if attr == 'class':
                tclass = value            
  
            if width == '530' and tclass == 'bez_okrajov':
                self.in_route_details_ = True 


    def start_img(self, attrs):
        width = None
        rowspan = None
        src = None
        
        for attr, value in attrs:
            if attr == 'src':
                src = value
            if attr == 'class' and value == 'netlac' and self.cur_route_:
                self.in_link_img_ = True
                  
            if width == '50' and rowspan == '2':
                self.in_link_ = True
                
        if self.in_link_img_:
            self.cur_link_img_ = src
            self.in_link_img_ = False  


    def handle_data(self, data):
        data = data.strip()
        if not data:
            return 
                    
        if data.find('Spojenie') != -1:
            if self.cur_route_:
                self.render_route()
                self.cur_conn_['routes'].append(self.cur_route_)                
                
                num_stops = len(self.cur_route_['stops'])

                self.cur_conn_['first_stop'] = {'lat': self.cur_conn_['routes'][0]['stops'][0]['lat'], 'lng': self.cur_conn_['routes'][0]['stops'][0]['lng']}
                self.cur_conn_['last_stop'] = {'lat': self.cur_route_['stops'][num_stops - 1]['lat'], 'lng': self.cur_route_['stops'][num_stops - 1]['lng']}
                try:                 
                    self.cur_conn_['title'] = u'%d. spojenie: cesta bude trvať %s a stáť %s' % (self.cur_conn_['id'], self.cur_conn_['duration'], self.cur_conn_['price'])           
                except KeyError, e:
                	print "got keyError exception: %s" % e                           
                self.conns_.append(self.cur_conn_)
                
                self.conn_id_ = self.conn_id_ + 1

            m = re.search(u'Spojenie (\d{1,2}\.\d{1,2}.\d{4}) (\d{1,2}:\d{1,2}) - (\d{1,2}:\d{1,2}) (\(.*?\))', data)
            if m:                
                self.cur_conn_ = {'id': self.conn_id_, 'date': m.group(1), 
                                  'start_time': m.group(2), 'end_time': m.group(3), 'duration': m.group(4), 'body': '', 'routes': []}
                self.route_id_ = 1
                self.cur_route_ = {'id': self.route_id_}                
        
        if data.find(u'Zóny') != -1:
            m = re.search(u'Zóny: (.*?) :: Cena: (.*)', data)
            if m:
                #self.cur_route_['zones'] = m.group(1)
                #self.cur_route_['price'] = m.group(2)
                self.cur_conn_['zones'] = m.group(1)
                self.cur_conn_['price'] = m.group(2)
            
        if self.in_link_:
            if self.in_walk_route_:
                self.render_route()
                self.cur_conn_['routes'].append(self.cur_route_)
                self.route_id_ = self.route_id_ + 1
                self.in_walk_route_ = False
                self.cur_route_ = {'id': self.route_id_}
            if self.cur_route_ and self.cur_route_.has_key('link'):
                self.render_route()
                self.cur_conn_['routes'].append(self.cur_route_)
                self.route_id_ = self.route_id_ + 1                
                self.cur_route_ = {'id': self.route_id_}
               
            self.cur_route_['link'] = data
            
            try:
                link = MHD_Link.objects.get(name = data)
                self.cur_route_['color'] = link.link_type.color
                self.cur_route_['icon'] = link.link_type.icon
            except ObjectDoesNotExist:
                print "link %s not in database!" % data
                
            self.cur_route_['stops'] = []
        
        if self.in_direction_:
            self.cur_route_['direction'] = data
            self.cur_route_['image'] = self.cur_link_img_
            self.in_direction_ = False
                            
        if data.find('Smer:') != -1:
            self.in_direction_ = True
        
        if self.in_stop_time_:
            if len(self.cur_route_['stops']) > 0 and self.cur_stop_:
                self.cur_route_['stops'].append(self.cur_stop_)
            self.cur_stop_ = {'time': data}
            
        if self.in_stop_name_ and not self.in_route_summary_:
            if not self.cur_stop_:
                print "missing stop object"
            self.cur_stop_['name'] = data
            
            mhd_link_direction = None                
            try:
                mhd_link_direction = MHD_Link_Direction.objects.get(link__name = self.cur_route_['link'], direction__contains = self.cur_route_['direction'])
            except ObjectDoesNotExist:
                print '[route parser]: direction %s not in database, need update.' % self.cur_route_['direction']
            except MultipleObjectsReturned:    
                print '[route parser]: got multiple mhd_link_direction entries for direction %s' % self.cur_route_['direction']
                 
            try:                 
                mhd_link_stop = MHD_Link_Stop.objects.get(link__name = self.cur_route_['link'], stop__name = self.cur_stop_['name'], direction = mhd_link_direction)
                self.cur_stop_['lat'] = mhd_link_stop.stop.lat
                self.cur_stop_['lng'] = mhd_link_stop.stop.lng
            except ObjectDoesNotExist:
                print '[route parser]: stop %s not in database, need update.' % data
            except MultipleObjectsReturned:
                mhd_link_stops = MHD_Link_Stop.objects.filter(link__name = self.cur_route_['link'], stop__name = self.cur_stop_['name'], direction = mhd_link_direction)
                self.cur_stop_['lat'] = mhd_link_stops[0].stop.lat
                self.cur_stop_['lng'] = mhd_link_stops[0].stop.lng
                
        
        if self.in_stop_zone_:
            self.cur_stop_['zone'] = data
            self.cur_route_['stops'].append(self.cur_stop_)
            self.cur_stop_ = None
            
        if self.in_walk_route_:
            self.cur_route_['direction'] = '%s %s ' % (self.cur_route_['direction'], data)
            self.cur_route_['image'] = self.cur_link_img_ 
            
        if data.find(u'Presun medzi nástupišťami') != -1:
            self.render_route()            
            self.cur_conn_['routes'].append(self.cur_route_)
            self.route_id_ = self.route_id_ + 1
            self.cur_route_ = {'id': self.route_id_, 'direction': data, 'stops': [], 'walking_route': True}
            try:
                link_type = MHD_Link_Type.objects.get(name = 'Nohy')
                self.cur_route_['color'] = link_type.color
                self.cur_route_['icon'] = link_type.icon
            except ObjectDoesNotExist:
                print "walking type not in database!" % data            
            self.in_walk_route_ = True    

                            
        if self.in_route_summary_:
            if self.cur_route_.has_key('summary'):
                self.cur_route_['summary'] = '%s, %s' % (self.cur_route_['summary'], data)
            else:
                self.cur_route_['summary'] = data
                
                
    def render_route(self):
        t = None           
        if not self.cur_route_.has_key('walking_route'):     
            self.cur_route_['walking_route'] = False
            self.cur_route_['first_stop'] = self.cur_route_['stops'][0]
            self.cur_route_['last_stop'] = self.cur_route_['stops'][len(self.cur_route_['stops']) - 1]
            t = get_template('mhd/stops_pane.html')
            self.cur_route_['stops_pane'] = t.render(Context({'stops': self.cur_route_['stops'][1:len(self.cur_route_['stops']) - 1]}))
            
            t = get_template('mhd/driving_route.html')
        else:            
            t = get_template('mhd/walking_route.html')
        self.cur_route_['stops_div'] = 'conn_%d_route_%d' % (self.cur_conn_['id'], self.cur_route_['id'])        
        self.cur_conn_['body'] = self.cur_conn_['body'] + t.render(Context({'route': self.cur_route_, 
                    'tmpl_id': self.cur_route_['stops_div']}))
        
